using System;
using System.Collections.Generic;
using System.Text;

namespace VerticalProcesses
{
    /// <summary>
    /// basic canopy unit
    /// </summary>
    public abstract class CanopyType
    {

        // public properties

        public string CName { get; set; }
        public double TimeStepHrs { get; set; }
        public double IntStorageRain { get; set; }
        public double IntStorageSnow { get; set; }
        public double IntEvapRain { get; set; }
        public double IntEvapSnow { get; set; }
        public double ThrfRain { get; set; }
        public double ThrfSnow { get; set; }
        public double ShortRadBelowCanopy { get; set; }

        public abstract void Update(DateTime timeStep, double gruRain, double gruSnow, double radiation, double ETpot, double latitude, double longitude, double elevation, double timeZone, double slope, double aspect);


    }

    public class SimpleRutter : CanopyType
    {

        public double MaxSnowInt { get; set; }
        public double MaxRainInt { get; set; }
        public double CSINTF { get; set; }
        public double CRINTF { get; set; }
        public double CrownClosure { get; set; }
        public double ALPHAC { get; set; }
        public double Dbh { get; set; }
        public double NStems { get; set; }
        public double HStem { get; set; }
        public double HCrown { get; set; }

        /// <summary>
        /// Updates canopy storages and calculates interception
        /// and throughfall
        /// </summary>
        /// <param name="gruRain"></param>
        /// <param name="gruSnow"></param>
        /// <param name="crownClosure"></param>
        /// <param name="ETpot"></param>
        public override void Update(DateTime timeStep, double gruRain, double gruSnow, double radiation, double ETpot, double latitude, double longitude, double elevation, double timeZone, double slope, double aspect)
        {

            IntercRain(gruRain, ETpot);
            IntercSnow(gruSnow, ETpot);
            ShortRadBelowCanopy = RadiationEq.CalcRadBelowCanopy(timeStep, radiation, TimeStepHrs, latitude, longitude, elevation, timeZone,
                slope, aspect, Dbh, NStems, HStem, HCrown, ALPHAC);
            //ShortRadBelowCanopy = RadiationEq.ClearSkySolarRadiation(timeStep, TimeStepHrs, latitude, longitude, elevation, timeZone, slope, aspect, Dbh, NStems, HStem, HCrown, ALPHAC);
        }

        /// <summary>
        /// Calculates snow interception and updates
        /// canopy compartment
        /// </summary>
        /// <param name="prec"></param>
        /// <param name="etPot"></param>
        /// <returns>updates canopy</returns>
        private void IntercSnow(double prec, double etPot)
        {
            double intRS;                                           // intercepted snow
            etPot = 0.5 / 24.0 * TimeStepHrs;// 5.0 * etPot; //georg: a real fudge factor to increase sublimation...

            double catchPrec = prec * CrownClosure * CSINTF;           // snowcatch proportional to crownclosure change the 0.6 once real data!!!
            double maxInt = MaxSnowInt * CrownClosure;             // maximum interception storage for a GRU proportional to crown closure
            double intStTemp = IntStorageSnow + catchPrec - etPot;   //dry the canopy with ETpot

            if (intStTemp > 0.0) //canopy is wet throughout time step
            {
                IntEvapSnow = etPot; //let the potential evaporation evaporate
                if (intStTemp > maxInt) //canopy is at max interception storage
                {
                    intRS = IntEvapSnow + maxInt - IntStorageSnow;
                }
                else //still storage left in canopy
                {
                    intRS = catchPrec;
                }

            }
            else //canopy dries during time step or stays dry
            {
                intRS = catchPrec;
                IntEvapSnow = IntStorageSnow + catchPrec;
            }

            // update canopy snow properties
            IntStorageSnow += intRS - IntEvapSnow;                  //canopy water balance
            ThrfSnow = prec - intRS;                                                // throughfall

        }


        /// <summary>
        /// Calculates rain interception and updates
        /// canopy compartment
        /// </summary>
        /// <param name="prec"></param>
        /// <param name="crownClosure"></param>
        /// <param name="etPot"></param>
        /// <returns>updates canopy</returns>
        private void IntercRain(double prec, double etPot)
        {
            double intRS;                                           //intercepted rain or snow
            double catchPrec = prec * CrownClosure * CRINTF;           //raincatch proportional to crownclosure change the 0.6 once real data!!!
            double maxInt = MaxRainInt * CrownClosure;             //maximum interception storage for a GRU proportional to crown closure
            double intStTemp = IntStorageRain + catchPrec - etPot;   //dry the canopy at ETpot

            if (intStTemp > 0.0) //canopy is wet throughout time step
            {
                IntEvapRain = etPot; //let the potential evaporation evaporate
                if (intStTemp > maxInt) //canopy is at max interception storage
                {
                    intRS = IntEvapRain + maxInt - IntStorageRain;
                }
                else //still storage left in canopy
                {
                    intRS = catchPrec;
                }

            }
            else //canopy dries during time step or stays dry
            {
                intRS = catchPrec;
                IntEvapRain = IntStorageRain + catchPrec;
            }

            // update canopy rain properties
            IntStorageRain += intRS - IntEvapRain;                  //canopy water balance
            ThrfRain = prec - intRS;                                // throughfall

        }

        public SimpleRutter(double crownClosure, double timeStepHrs, double maxSnowInt, double maxRainInt,
            double CRINTF, double CSINTF, double ALPHAC, double dbh, double nStems, double hStem, double hCrown)
        {

            this.CrownClosure = crownClosure;
            this.TimeStepHrs = timeStepHrs;
            this.MaxSnowInt = maxSnowInt;
            this.MaxRainInt = maxRainInt;
            this.CRINTF = CRINTF;
            this.CSINTF = CSINTF;
            this.ALPHAC = ALPHAC;
            this.Dbh = dbh;
            this.NStems = nStems;
            this.HStem = hStem;
            this.HCrown = hCrown;
        }


    }


}
